#include "opc_fun.h"

/**
 * global variable
 * 
 * these varibale have initialized in the main function,
 * before used by other code
*/
extern modbus_t *ctx;
extern sqlite3 *db;
extern UA_Server *haussentech_opc_server;
extern UA_HistoryDataGathering hs_gather;
extern dlt645_t dlt645;
/**
 * 全局变量，用来存储sql的查询结果（经过数据个是转哈un，可以直接使用）
*/
struct sql_query_result_object sql_result;
/*
    temp storage SQLite query result 
*/
int var_id;
char var_name[64];
char var_type[64];
bool sql_cb_done;
int begin_addr;
int offset_range;
char protocol[16];
//internal protocol

/*dlt_645*/
char specification[16];
char reg_address[32];
char data_field[256];
/*dlt_645*/

/*iec_104*/
bool handler_done = false;
int ioa_buffer[2048]={0};
float ioa_float_buffer[2048]={0};
bool ioa_bool_buffer[2048]={0};
/*iec_104*/
/*
   查询SQL数据库里面每个变量对应的底层协议参数
*/
static int Callback_get_protocol_specify_config(void *data, int argc, char **argv, char **azColName){
    int i;
    fprintf(stderr, "%s: ", (const char*)data);
    for(i=0; i<argc; i++){
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
        if(0 == strcmp(azColName[i], "var_type")){
                //strcpy(var_type,argv[i]);
        }
        if(0 == strcmp(azColName[i], "name")){
            strcpy(sql_result.name,argv[i]);
            //strcpy(var_name,argv[i]);
        }
        //根据对应的协议进行查询的操作
        if(0 == strcmp(sql_result.protocol, "modbus_tcp")){
            if(0 == strcmp(azColName[i], "ip_address")){
                strcpy(sql_result.ip_address,argv[i]);
            }else if(0 == strcmp(azColName[i], "port")){
                sql_result.port = atoi(argv[i]);
            }else if(0 == strcmp(azColName[i], "register_type")){
                strcpy(sql_result.register_type,argv[i]);
            }else if(0 == strcmp(azColName[i], "begin_address")){
                sql_result.begin_address = atoi(argv[i]);
            }else if(0 == strcmp(azColName[i], "offset_range")){
                sql_result.offset_range = atoi(argv[i]);
            }
        }else if(0 == strcmp(sql_result.protocol,"iec_104")){
            //上面的strcmp需要和sql里面配置的内容相对应,需要把前面的iec前缀去掉
            if(0 == strcmp(azColName[i], "ip_address")){
                strcpy(sql_result.iec_ip_address,argv[i]);
            } 
            if(0 == strcmp(azColName[i], "port")){
                sql_result.iec_port = atoi(argv[i]);
            } 
            if(0 == strcmp(azColName[i], "typeid")){
                strcpy(sql_result.iec_typeid,argv[i]);
            } 
            if(0 == strcmp(azColName[i], "cot")){
                strcpy(sql_result.iec_cot,argv[i]);
            }
            if(0 == strcmp(azColName[i], "param")){
                printf("sql_result.iec_param:%s",argv[i]);
                strcpy(sql_result.iec_param,argv[i]);
            }                            
        }else if(0 == strcmp(sql_result.protocol,"modbus_rtu")){
            if(0 == strcmp(azColName[i], "rtu_param")){
                printf("rtu_param:%s",argv[i]);
                strcpy(sql_result.rtu_param,argv[i]);
            }              
        }else if(0 == strcmp(sql_result.protocol,"dlt_645")){
            if(0 == strcmp(azColName[i], "param")){
                printf("dlt645_param:%s\n",argv[i]);
                strcpy(sql_result.dlt645_param,argv[i]);
            }            
        }
    }
    printf("\n");
    sql_cb_done = true;
    return 0;
}

static int Callback_sql_selet_get_var_protocol(void *data, int argc, char **argv, char **azColName){
    int i;
    fprintf(stderr, "%s: ", (const char*)data);
    for(i=0; i<argc; i++){
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
        if(0 == strcmp(azColName[i], "protocol")){
            strcpy(sql_result.protocol,argv[i]);
        }
    }
    printf("\n");
    sql_cb_done = true;
    return 0;
}


/*
add more if else case to suit more protocol situation
*/
void sql_select_get_var_protocol_config(char* name){
    //query databse get config first
    const char* data = "Callback function called";

    char sql[512] = "select * from opc_var_config,";

    /*
        modify here
    */
    if(0 == strcmp(sql_result.protocol, "modbus_tcp")){
        strcat(sql,"modbus_tcp");
        strcat(sql," WHERE modbus_tcp.name = opc_var_config.name AND opc_var_config.name = '");
    }else if(0 == strcmp(sql_result.protocol, "dlt_645")){
        strcat(sql,"dlt_645");
        strcat(sql," WHERE dlt_645.name = opc_var_config.name AND opc_var_config.name = '");        
    }else if(0 == strcmp(sql_result.protocol, "iec_104")){
        strcat(sql,"iec_104");
        strcat(sql," WHERE iec_104.name = opc_var_config.name AND opc_var_config.name = '");        
    }else if(0 == strcmp(sql_result.protocol, "modbus_rtu")){
        strcat(sql,"modbus_rtu");
        strcat(sql," WHERE modbus_rtu.name = opc_var_config.name AND opc_var_config.name = '");          
    }
    strcat(sql,name);
    char* sentence_end = "';";
    strcat(sql,sentence_end);
    // modbus_tcp_reg_config where name = ;"
    /* Execute SQL statement */
    printf("[SQL]%s\n",sql);
    char *zErrMsg = 0;
    int rc;
    // modify callback
    rc = sqlite3_exec(db, sql, Callback_get_protocol_specify_config, (void*)data, &zErrMsg);
    if( rc != SQLITE_OK ){
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        //开发状态的代码，暂时关闭程序重启机制
        //execve("opc", NULL, NULL);
        //exit(0);
        sqlite3_free(zErrMsg);
        return;
    }else{
        fprintf(stdout, "SQL select done successfully\n");
        return;
    }
}
/*
the purpose of the funciton is to get identify aka var_name
from the current opc client query session,
it can be used in the upcoming update process to select match parm in the sqlite database
because we use var_name as unique key.
*/
bool var_been_read = false;
bool read_lock = false;
void beforeReadTime(UA_Server *server,
               const UA_NodeId *sessionId, void *sessionContext,
               const UA_NodeId *nodeid, void *nodeContext,
               const UA_NumericRange *range, const UA_DataValue *data) {
    // [DEBUG] UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
    //     "UA_NodeId :%u",nodeid->namespaceIndex);
    // [DEBUG UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
    //     "sessionId :%u",sessionId->namespaceIndex);     
    // [DEBUG] UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
    //     "var_name :%s",nodeid->identifier);     
    //var_been_read的更改，必须放在OPC_Update_Value函数前面，才能保证进行变更
    if(read_lock == false){
        var_been_read = true;
        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
            "\n[beforeReadTime]\n");
        int name_len = nodeid->identifier.string.length;
        UA_Byte* q=nodeid->identifier.string.data;
        char callback_buf[128]={0};
        memcpy(callback_buf, q, name_len);
        //[DEBUG]
        printf("[beforeReadTime_callback_buf]: %s\n",callback_buf);
        //暂时注释，用来观察值是否成功写入
        OPC_Update_Value(server,callback_buf);
    }   
}

//从参数里面的data才能够读取client传递过来的量
void afterWriteTime(UA_Server *server,
               const UA_NodeId *sessionId, void *sessionContext,
               const UA_NodeId *nodeid, void *nodeContext,
               const UA_NumericRange *range, const UA_DataValue *data) {
    if(var_been_read == true){
        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                "afterWriteTime\n[The variable was updated]\n");
        var_been_read = false; 
    }else{
        read_lock = true;
        //对读操作加锁，否则会影响交互过程
        //没有出现读取值的情况时打印这条信息
         UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                "afterWriteTime modbus write\n[OPC Write]\n");  
        int name_len = nodeid->identifier.string.length;
        UA_Byte* q=nodeid->identifier.string.data;
        char callback_buf[128]={0};
        memcpy(callback_buf, q, name_len);
        //[DEBUG]
        printf("[afterWriteTime_callback_buf]: %s\n",callback_buf);
        //测试代码
        // if(data->hasValue==true){
        //     UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
        //         "\nhave value\n");    
        //     UA_Variant array_tab = data->value;
        //     printf("arrayLength:%d\n",array_tab.arrayLength);
        //     uint16_t* array_var = (uint16_t*)array_tab.data;
        //     for(int i=0;i<array_tab.arrayLength;i++){
        //         printf("%x\n",array_var[i]);
        //     }
        // }else{
        //  UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
        //         "\ndon't have value\n");              
        // }
        //传入data->value用于后续向modbus寄存器写入数据
        OPC_Write_Value(server,callback_buf,data->value);  
        var_been_read = false;  
        read_lock = false;
        //完成写操作，解除读取锁
    }
    //一律把这个bool变量设置为false
    
}

/*
目前的做法是查询数据库，但是后续可以考虑通过全局变量的方式来获取之前的参数
在新增变量之前，首先就通过函数传递的方式提供了变量的底层协议类型
*/
int OPC_addVariable(UA_Server *server,char* name,char * parm_protocol) {
    //strcpy(protocol,parm_protocol);
    strcpy(sql_result.protocol,parm_protocol);
    sql_cb_done = false;
    //获取底层的参数进行配置，保存到了一个专门的结构体中
    //opc的name，是作为多张表在联合查询时的一个唯一的主键存在的
    sql_select_get_var_protocol_config(name);
    while (!sql_cb_done)
    {
        //wait cb done get config info
        /* code */
    }
    //这个变量是创建所有的量都是通用的，并且允许读写同步进行
    UA_VariableAttributes attr = UA_VariableAttributes_default;  
    //默认支持对变量的历史数据进行追溯  
    //attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
    attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE | UA_ACCESSLEVELMASK_HISTORYREAD;
    attr.historizing = true;
    /*
    * At the end we register the node for gathering data in the database.
    */

    if(0==strcmp(sql_result.protocol,"dlt_645")){
        cJSON* dlt645_param_json = cJSON_Parse(sql_result.dlt645_param);
        cJSON* dic = cJSON_GetObjectItemCaseSensitive(dlt645_param_json, "dic");
        if(dic->valueint == DIC_0){
            //根据offset_range来决定创建的数组的宽度
            int array_size = 1;
            UA_Float *values = (UA_Float *) UA_Array_new(array_size, &UA_TYPES[UA_TYPES_FLOAT]);
            //使用for循环为数组提供初始值
            for(int i=0;i<array_size;i++){
                values[i]=199.09;
            }
            //数组的数据类型也要进行变更为UA_TYPES_INT16
            opc_public_add_var_finish_op(server,sql_result.name,values,array_size,UA_TYPES_FLOAT); 
            cJSON_Delete(dlt645_param_json); 
            return 0;  
        }        
    }
    if(0==strcmp(sql_result.protocol,"modbus_tcp")){
        ctx = modbus_new_tcp(sql_result.ip_address, sql_result.port);
        if(ctx == NULL){
            fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
            modbus_free(ctx);
            return -1;      
        }
        modbus_set_debug(ctx, TRUE);
        if (modbus_connect(ctx) == -1) {
            fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
            modbus_free(ctx);
            return -1;
            //return -1;
        }
        //再新增变量的时候，只测试通信是否正常，完成后即刻释放连接
        modbus_close(ctx);
        modbus_free(ctx);
        if(0==strcmp(sql_result.register_type,"holding_register")||
            0==strcmp(sql_result.register_type,"input_register")
        ){
            //根据offset_range来决定创建的数组的宽度
            int array_size = sql_result.offset_range;
            UA_UInt16 *values = (UA_UInt16 *) UA_Array_new(array_size, &UA_TYPES[UA_TYPES_INT16]);
            //使用for循环为数组提供初始值
            for(int i=0;i<array_size;i++){
                values[i]=0x1234;
            }
            //数组的数据类型也要进行变更为UA_TYPES_INT16
            opc_public_add_var_finish_op(server,sql_result.name,values,array_size,UA_TYPES_INT16);  
            return 0;      
        }else if(0==strcmp(sql_result.register_type,"coil") ||
            0==strcmp(sql_result.register_type,"discrete_input")){
                //是根据底层modbus仓库的是喜爱年，为这两类寄存器分配的是无符号的整数
                int array_size = sql_result.offset_range;
                //因为类型是保持寄存器，所以数组的数据类型就设置uint16
                UA_Byte *values = (UA_Byte *) UA_Array_new(array_size, &UA_TYPES[UA_TYPES_BYTE]);
                //使用for循环为数组提供初始值
                for(int i=0;i<array_size;i++){
                    values[i]=0xFF;
                }
                //数组的数据类型也要进行变更为UA_TYPES_BYTE
                opc_public_add_var_finish_op(server,sql_result.name,values,array_size,UA_TYPES_BYTE);  
                return 0;                
            }
    }else if(0==strcmp(sql_result.protocol,"modbus_rtu")){
        cJSON* rtu_param_json = cJSON_Parse(sql_result.rtu_param);
        cJSON* device = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "device");
        cJSON* baud = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "baud");
        cJSON* parity = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "parity");
        cJSON* data_bit = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "data_bit");
        cJSON* stop_bit = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "stop_bit");
        cJSON* server_id = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "server_id");
        cJSON* register_type = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "register_type");
        cJSON* begin_address = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "begin_address");
        cJSON* offset_range = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "offset_range");
        //char* parity_char = (char*)malloc(sizeof(char)*8);
        //char parity_char[8];
        //strcpy(parity_char,parity->valuestring);
        //parity_char = parity->valuestring;
        // if(0==strcmp(parity->valuestring,"N")){
        //     parity_char='N';
        // }
        printf("%s %d %c %d %d\n",device->valuestring, 
            baud->valueint, 
            *(parity->valuestring), 
            data_bit->valueint, 
            stop_bit->valueint);
        ctx = modbus_new_rtu(device->valuestring, 
            baud->valueint, 
            *(parity->valuestring), 
            data_bit->valueint, 
            stop_bit->valueint);
        modbus_set_slave(ctx, server_id->valueint);

        if(ctx == NULL){
            fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
            modbus_free(ctx);
            return -1;      
        }
        modbus_set_debug(ctx, TRUE);
        if (modbus_connect(ctx) == -1) {
            fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
            modbus_free(ctx);
            return -1;
            //return -1;
        }
        //再新增变量的时候，只测试通信是否正常，完成后即刻释放连接
        modbus_close(ctx);
        modbus_free(ctx); 
        if(0==strcmp(register_type->valuestring,"holding_register")||
            0==strcmp(register_type->valuestring,"input_register")
        ){
            //根据offset_range来决定创建的数组的宽度
            int array_size = offset_range->valueint;
            UA_UInt16 *values = (UA_UInt16 *) UA_Array_new(array_size, &UA_TYPES[UA_TYPES_INT16]);
            //使用for循环为数组提供初始值
            for(int i=0;i<array_size;i++){
                values[i]=0x1234;
            }
            //数组的数据类型也要进行变更为UA_TYPES_INT16
            opc_public_add_var_finish_op(server,sql_result.name,values,array_size,UA_TYPES_INT16); 
            cJSON_Delete(rtu_param_json); 
            return 0;      
        }else if(0==strcmp(register_type->valuestring,"coil") ||
            0==strcmp(register_type->valuestring,"discrete_input")){
            //是根据底层modbus仓库的是喜爱年，为这两类寄存器分配的是无符号的整数
            int array_size = offset_range->valueint;
            //因为类型是保持寄存器，所以数组的数据类型就设置uint16
            UA_Byte *values = (UA_Byte *) UA_Array_new(array_size, &UA_TYPES[UA_TYPES_BYTE]);
            //使用for循环为数组提供初始值
            for(int i=0;i<array_size;i++){
                values[i]=0xFF;
            }
            //数组的数据类型也要进行变更为UA_TYPES_BYTE
            opc_public_add_var_finish_op(server,sql_result.name,values,array_size,UA_TYPES_BYTE);
            cJSON_Delete(rtu_param_json);
            return 0;                
        }
    }else if(0==strcmp(sql_result.protocol,"iec_104")){
        if(0==strcmp(sql_result.iec_typeid,"M_SP_NA_1")){
            cJSON* iec104_param = cJSON_Parse(sql_result.iec_param);
            if(iec104_param == NULL){
                printf("parse fail\n");
            }else{
                printf("parse successful\n");
            }
            cJSON* iec104_ios = cJSON_GetObjectItemCaseSensitive(iec104_param, "ios");
            int array_size = cJSON_GetArraySize(iec104_ios);
            printf("array_size:%d",array_size);
            UA_Boolean* values = (UA_Boolean*) UA_Array_new(array_size, &UA_TYPES[UA_TYPES_BOOLEAN]);
            //使用for循环为数组提供初始值
            for(int i=0;i<array_size;i++){
                values[i]=false;
            }
            opc_public_add_var_finish_op(server,sql_result.name,values,array_size,UA_TYPES_BOOLEAN);
            //opc_public_add_var_finish_op(server,sql_result.name,values,array_size);
            return 0;  
        }
        if(0==strcmp(sql_result.iec_typeid,"M_ME_NC_1")){
            cJSON* iec104_param = cJSON_Parse(sql_result.iec_param);
            if(iec104_param == NULL){
                printf("parse fail\n");
            }else{
                printf("parse successful\n");
            }
            cJSON* iec104_ios = cJSON_GetObjectItemCaseSensitive(iec104_param, "ios");
            int array_size = cJSON_GetArraySize(iec104_ios);
            printf("array_size:%d",array_size);
            UA_Float* values = (UA_Float*) UA_Array_new(array_size, &UA_TYPES[UA_TYPES_FLOAT]);
            //使用for循环为数组提供初始值
            for(int i=0;i<array_size;i++){
                values[i]=220.00;
            }
            opc_public_add_var_finish_op(server,sql_result.name,values,array_size,UA_TYPES_FLOAT);
            //opc_public_add_var_finish_op(server,sql_result.name,values,array_size);
            return 0;  
        }
        //在保证协议的类型时IEC104的时候，之后去查询typeid
        if(0==strcmp(sql_result.iec_typeid,"M_ME_NB_1")){
            //根据iec_offset_range来决定创建的数组的宽度
            cJSON* iec104_param = cJSON_Parse(sql_result.iec_param);
            cJSON* iec104_ios = cJSON_GetObjectItemCaseSensitive(iec104_param, "ios");
            int array_size = cJSON_GetArraySize(iec104_ios);
            printf("array_size:%d",array_size);
            //因为类型是保持寄存器，所以数组的数据类型就设置UA_UInt32
            UA_UInt32* values = (UA_UInt32*) UA_Array_new(array_size, &UA_TYPES[UA_TYPES_INT32]);
            //使用for循环为数组提供初始值
            for(int i=0;i<array_size;i++){
                values[i]=416;
            }
            //数组的数据类型也要进行变更为UA_UInt32
            UA_Variant_setArray(&attr.value, values, array_size, &UA_TYPES[UA_TYPES_INT32]);
            attr.valueRank = UA_VALUERANK_ANY;
            // We want a 1-dimensional array with 2 values
            //创建的数组还可以设置纬度，说明可以创建矩阵
            UA_UInt32 myArrayDimensions[1] = {array_size};
            attr.value.arrayDimensions = myArrayDimensions;
            attr.value.arrayDimensionsSize = 1;
            //创建变量作为数组的名称
            attr.displayName = UA_LOCALIZEDTEXT("locale",sql_result.name);
            UA_StatusCode retval = UA_Server_addVariableNode(server,
                                            UA_NODEID_STRING(1, sql_result.name), // new node id
                                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), // parent node
                                            UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), // reference type
                                            UA_QUALIFIEDNAME(1, sql_result.name), // node browse name
                                            UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
                                            attr, NULL, NULL); 
            //设置变量对应的回调函数，来应对读和写两种情况
            UA_NodeId currentNodeId = UA_NODEID_STRING(1, sql_result.name);
            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,         // [LEGACY DEBUG CODE]
                "[Add node]UA_NodeId :%u",currentNodeId.namespaceIndex);    // [LEGACY DEBUG CODE]   
            UA_ValueCallback callback;
            callback.onRead = beforeReadTime;//don't need change
            callback.onWrite = afterWriteTime;//don't need change
            UA_Server_setVariableNode_valueCallback(server, currentNodeId, callback);  
            //避免内存泄漏 
            cJSON_Delete(iec104_param); 
            return 0;
            // UA_Int16* var_array = (UA_Int16*)UA_Array_new(sql_result.offset_range, &UA_TYPES[UA_TYPES_INT16]);
            // UA_Server_readValue(server, currentNodeId, var_array);
            // //遍历输出，证明这个值被修改了
            // for(int i=0;i<sql_result.offset_range;i++){
            //     printf("write var: %x\n",var_array[i]);
            // }   
        }else if(0==strcmp(sql_result.iec_typeid,"C_SE_NB_1")){
            printf("\n%s\n",sql_result.iec_param);
            cJSON* iec104_param = cJSON_Parse(sql_result.iec_param);
            if(iec104_param == NULL){
                printf("parse fail\n");
            }else{
                printf("parse successful\n");
            }
            cJSON* iec104_ios = cJSON_GetObjectItemCaseSensitive(iec104_param, "ios");
            int array_size = cJSON_GetArraySize(iec104_ios);
            printf("array_size:%d",array_size);
            UA_UInt32* values = (UA_UInt32*) UA_Array_new(array_size, &UA_TYPES[UA_TYPES_INT32]);
            //使用for循环为数组提供初始值
            for(int i=0;i<array_size;i++){
                values[i]=418;
            }
            //opc_public_add_var_finish_op(server,sql_result.name,values,array_size);
            return 0;    
        }else if(0==strcmp(sql_result.iec_typeid,"C_SE_NC_1")){
            //Setpoint command, normalized value
            //printf("\n%s\n",sql_result.iec_param);
            cJSON* iec104_param = cJSON_Parse(sql_result.iec_param);
            if(iec104_param == NULL){
                printf("parse fail\n");
            }else{
                printf("parse successful\n");
            }
            cJSON* iec104_ios = cJSON_GetObjectItemCaseSensitive(iec104_param, "ios");
            int array_size = cJSON_GetArraySize(iec104_ios);
            printf("array_size:%d",array_size);
            UA_Float* values = (UA_Float*) UA_Array_new(array_size, &UA_TYPES[UA_TYPES_FLOAT]);
            //使用for循环为数组提供初始值
            for(int i=0;i<array_size;i++){
                values[i]=123.14159;
            }
            opc_public_add_var_finish_op(server,sql_result.name,values,array_size,UA_TYPES_FLOAT);
            //opc_public_add_var_finish_op(server,sql_result.name,values,array_size);
            return 0;  
        }
    }
    return -1;
   //
    // UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, sql_result.name);
    // UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, sql_result.name);
    // UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
    // UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
    // UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
    // parentReferenceNodeId, myIntegerName,
    // UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),attr, NULL, NULL);
    //bind callback function

}

void opc_public_add_var_finish_op(UA_Server *server,char* opc_var_name,UA_UInt32* values,int array_size,int opc_data_type){
    UA_VariableAttributes attr = UA_VariableAttributes_default;    
    attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE | UA_ACCESSLEVELMASK_HISTORYREAD;
    attr.historizing = true;
    //UA_Variant_setArray(&attr.value, values, array_size, &UA_TYPES[UA_TYPES_INT32]);
    UA_Variant_setArray(&attr.value, values, array_size, &UA_TYPES[opc_data_type]);
    attr.valueRank = UA_VALUERANK_ANY;
    // We want a 1-dimensional array with 2 values
    //创建的数组还可以设置纬度，说明可以创建矩阵
    UA_UInt32 myArrayDimensions[1] = {array_size};
    attr.value.arrayDimensions = myArrayDimensions;
    attr.value.arrayDimensionsSize = 1;
    //创建变量作为数组的名称
    attr.displayName = UA_LOCALIZEDTEXT("locale",opc_var_name);
    UA_StatusCode retval = UA_Server_addVariableNode(server,
                                    UA_NODEID_STRING(1, opc_var_name), // new node id
                                    UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), // parent node
                                    UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), // reference type
                                    UA_QUALIFIEDNAME(1, opc_var_name), // node browse name
                                    UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
                                    attr, NULL, NULL); 
    // UA_StatusCode retval = UA_Server_addVariableNode(server,
    //                                 UA_NODEID_STRING(1, opc_var_name), // new node id
    //                                 UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), // parent node
    //                                 UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), // reference type
    //                                 UA_QUALIFIEDNAME(1, opc_var_name), // node browse name
    //                                 UA_NODEID_NUMERIC(0, UA_NS0ID_DATAVALUE),
    //                                 attr, NULL, NULL);                          
    //设置变量对应的回调函数，来应对读和写两种情况
    UA_NodeId currentNodeId = UA_NODEID_STRING(1, opc_var_name);
    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,         // [LEGACY DEBUG CODE]
        "[Add node]UA_NodeId :%u",currentNodeId.namespaceIndex);    // [LEGACY DEBUG CODE]   
    UA_ValueCallback callback;
    callback.onRead = beforeReadTime;//don't need change
    callback.onWrite = afterWriteTime;//don't need change
    UA_Server_setVariableNode_valueCallback(server, currentNodeId, callback); 
    //创建和变量匹配的数据库
    UA_HistorizingNodeIdSettings setting;
    //指定保存历史数据的数据库的文件名
    //char* str="./data_storage";
    //strcat(opc_var_name,".db");
    //setting.historizingBackend = UA_HistoryDataBackend_sqlite("");
    //setting.historizingBackend = UA_HistoryDataBackend_sqlite(opc_var_name);
    //使用数据库作为后端的意义不是很多，因为变量的id不是固定的，重启以后就无法有效的利用
    /*
        另外开发一个应用，或者开一个线程，把这些数据存储到数据库中
        或者直接值入一个历史记录的功能，直接在读写数据的时候，就把产生变更的数据存储到自己设计的数据库中
    */
    setting.historizingBackend = UA_HistoryDataBackend_Memory(3, 100);
    setting.maxHistoryDataResponseSize = 100;
    setting.historizingUpdateStrategy = UA_HISTORIZINGUPDATESTRATEGY_VALUESET;
    retval = hs_gather.registerNodeId(server, hs_gather.context, &currentNodeId, setting);  
}
/*
根据变量名通过查询数据库获得其对应的底层协议
*/
void sql_selet_get_var_protocol(char* name){
    //query databse get config first
    const char* data = "Callback function called";
    //emphasis on the sql sentence modify
    //char* sql = "SELECT * from opc_var_config";
    //"select name from opc_var_config;"
    //every record,wiil call add variable function
    char sql[512] = "SELECT protocol FROM opc_var_config WHERE name = '";
    strcat(sql,name);
    char* sentence_end = "';";
    strcat(sql,sentence_end);
    printf("\n[SQL]%s\n",sql);
    char *zErrMsg = 0;
    int rc;
    rc = sqlite3_exec(db, sql, Callback_sql_selet_get_var_protocol, (void*)data, &zErrMsg);
    if( rc != SQLITE_OK ){
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        //execve("opc", NULL, NULL);
        sqlite3_free(zErrMsg);
    }else{
        fprintf(stdout, "SQL select done successfully\n");
    }
}

//通过json来存储opc变量的历史数据
char* OPC_var_to_JSON(void* opc_val_array,int array_size,int format){
        //uint16在转换成int的时候会遇到很多的问题，要换成hex string的方式
    //后续json读取的时候也要把字符串转回数值
    uint16_t* u16_client_parm_array = NULL;
    uint8_t* u8_client_parm_array = NULL;
    float* float_client_parm_array = NULL;
    if(format == UA_TYPES_INT16){
        u16_client_parm_array = (uint16_t*)opc_val_array; 
    }else if(format == UA_TYPES_BYTE){
        u8_client_parm_array = (uint8_t*)opc_val_array; 
    }else if(format == UA_TYPES_FLOAT){
        float_client_parm_array = (float*)opc_val_array;
    }
    char* hex_str_arr[array_size];  
    //这个括号里面是可以使用变量的
    for(int i=0;i<array_size;i++)  
    {  
        //存储每个变量字符表示的空间，都是固定的
        hex_str_arr[i]=(char*)malloc(32*sizeof(char)); 
        //采用高位补0，补齐四个十六进制数的策略，两个字节
        //沿用OPC UA仓库提供的数据类型定义
        if(format == UA_TYPES_INT16){
            sprintf(hex_str_arr[i],"0x%04X",u16_client_parm_array[i]);
        }else if(format == UA_TYPES_BYTE){
            sprintf(hex_str_arr[i],"0x%04X",u8_client_parm_array[i]);
        }else if(format == UA_TYPES_FLOAT){
            sprintf(hex_str_arr[i],"%3.2f",float_client_parm_array[i]);
            //float_client_parm_array = (float*)opc_val_array
        }
        //后续json读取的时候也要把字符串转回数值
    }
    cJSON* data_json = cJSON_CreateObject();
    /* 添加一条字符串类型的JSON数据(添加一个链表节点) */
    cJSON *data_array = cJSON_CreateStringArray(hex_str_arr, array_size);
    cJSON_AddItemToObject(data_json, "data_array", data_array);
    char* json_str = cJSON_Print(data_json);
    printf("[JSON]\n%s\n",json_str);  
    //释放cjson字符串 
    cJSON_Delete(data_json);
    for(int i=0;i<array_size;i++)  
    {  
        //释放每个字符串占据的内存空间
        free(hex_str_arr[i]);
    }
    //返回转换成字符串的json对象
    return json_str;
}

void OPC_Write_Value(UA_Server *server,char* var_name,UA_Variant client_parm) {
    //获取变量名对应的协议类型
    sql_cb_done = false;
    sql_selet_get_var_protocol(var_name);
    while (!sql_cb_done)
    {
        //sql_cb_done为全局变量，循环等待回调函数执行结束，将其设为真
        //继续执行，目的就是把涉及到回调函数的场景，能够变成顺序执行
        //而不是陷入层层嵌套的回调地狱
    }   
    sql_cb_done = false;
    sql_select_get_var_protocol_config(var_name);
    while (!sql_cb_done)
    {

    }
    if(0==strcmp(sql_result.protocol,"iec_104")){
        handler_done = false;

        //准备把OPC客户端发来的参数传递进去
        CS104_Connection con = CS104_Connection_create(
            sql_result.iec_ip_address, sql_result.iec_port);
        printf("Connecting to: %s:%i\n", sql_result.iec_ip_address, sql_result.iec_port);
        CS101_AppLayerParameters alParams = CS104_Connection_getAppLayerParameters(con);
        alParams->originatorAddress = 3;
        CS104_Connection_setConnectionHandler(con, connectionHandler, NULL);
        CS104_Connection_setASDUReceivedHandler(con, asduReceivedHandler, NULL);
        /* uncomment to log messages */
        //CS104_Connection_setRawMessageHandler(con, rawMessageHandler, NULL);

        if (CS104_Connection_connect(con)) {
            printf("Connected!\n");

            CS104_Connection_sendStartDT(con);
            /*
            开始读取读取JSON里面的数据,首先获得大的对喜爱嗯
            */
            CS101_ASDU newAsdu = CS101_ASDU_create(alParams, false,atoi(sql_result.iec_cot),
                            0, 1, false, false);
            cJSON* p_param = cJSON_Parse(sql_result.iec_param);
            //获取客户端传来的是UA_Variant client_parm，获取里面data，转换出和客户端传数组时对应的个时
            printf("arrayLength:%d\n",client_parm.arrayLength);
            //参数进来的时候是int，这里就要用int，不然会出问题
            cJSON* p_ios = cJSON_GetObjectItemCaseSensitive(p_param, "ios");
            cJSON* p_select = cJSON_GetObjectItemCaseSensitive(p_param, "select");
            if(0==strcmp(sql_result.iec_typeid,"C_SE_NB_1")){
                int* client_parm_array = (int*)client_parm.data;  
                const cJSON *p_io;
                int index = 0;
                cJSON_ArrayForEach(p_io, p_ios){
                    printf("one loop\n");
                    printf("%d\n",client_parm_array[index]);
                    cJSON *p_ioa = cJSON_GetObjectItemCaseSensitive(p_io, "ioa");
                    cJSON *p_value = cJSON_GetObjectItemCaseSensitive(p_io, "value");
                    CS101_ASDU_addInformationObject(newAsdu, (InformationObject)
                        SetpointCommandScaled_create(NULL, p_ioa->valueint, client_parm_array[index], cJSON_IsTrue(p_select), 0));
                    index++;
                }
            }else if(0==strcmp(sql_result.iec_typeid,"C_SE_NA_1")){
                float* client_parm_array = (float*)client_parm.data; 
                //UA_Byte* client_parm_array = (UA_Byte*)client_parm.data;
                //看一下值传递的情况
                // for(int i=0;i<8;i++){
                //     printf("%X\n",client_parm_array[i]);
                // }
                const cJSON *p_io;
                int index = 0;
                cJSON_ArrayForEach(p_io, p_ios){
                    printf("SetpointCommandNormalized\n");
                    printf("%f\n",client_parm_array[index]);
                    cJSON *p_ioa = cJSON_GetObjectItemCaseSensitive(p_io, "ioa");
                    cJSON *p_value = cJSON_GetObjectItemCaseSensitive(p_io, "value");
                    //查找匹配和对应的指令
                    CS101_ASDU_addInformationObject(newAsdu, (InformationObject)
                        SetpointCommandNormalized_create(NULL, p_ioa->valueint, client_parm_array[index], cJSON_IsTrue(p_select), 0));
                    index++;
                }                
            }else if(0==strcmp(sql_result.iec_typeid,"C_SE_NC_1")){
                float* client_parm_array = (float*)client_parm.data; 
                //UA_Byte* client_parm_array = (UA_Byte*)client_parm.data;
                //看一下值传递的情况
                // for(int i=0;i<8;i++){
                //     printf("%X\n",client_parm_array[i]);
                // }
                const cJSON *p_io;
                int index = 0;
                cJSON_ArrayForEach(p_io, p_ios){
                    printf("Setpoint command, short floating point value\n");
                    printf("%f\n",client_parm_array[index]);
                    cJSON *p_ioa = cJSON_GetObjectItemCaseSensitive(p_io, "ioa");
                    cJSON *p_value = cJSON_GetObjectItemCaseSensitive(p_io, "value");
                    //查找匹配和对应的指令
                    CS101_ASDU_addInformationObject(newAsdu, (InformationObject)
                        SetpointCommandShort_create(NULL, p_ioa->valueint, client_parm_array[index], cJSON_IsTrue(p_select), 0));
                    index++;
                }                
            }
            CS104_Connection_sendASDU(con, newAsdu);
        }
        else{
            printf("Connect failed!\n");
        }
        CS104_Connection_destroy(con);
        printf("exit\n");  
        //因为写入操作，不期待服务端的返回值，所以不需要等待handler获取到相应的将诶国
        // while(!handler_done){

        // }       
        // //针对两种情况,一定要注意全称，不能多一个空格
        // if(0==strcmp(sql_result.iec_typeid,"M_ME_NB_1") || 
        //     0==strcmp(sql_result.iec_typeid,"C_SE_NB_1")){
        //     UA_Variant value;
        //     //将读取的数组变更为OPC UA可以接受的形式,要注意UA_TYPES_INT32
        //     //把缓冲区里面的值，标记上起始地址和偏移范围以后
        //     UA_Variant_setArray(&value,ioa_buffer+100,2, &UA_TYPES[UA_TYPES_INT32]);
        //     //UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-value-callback");
        //     //UA_NodeId currentNodeId = UA_NODEID_STRING(1, "HaoSheng");
        //     UA_NodeId currentNodeId = UA_NODEID_STRING(1,var_name);
        //     UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
        //     "[final]UA_NodeId :%u",currentNodeId.namespaceIndex);   
        //     //将新的值写入到之前的变量中    
        //     UA_Server_writeValue(server, currentNodeId, value);
        // }  
        //Thread_sleep(1000);
    }
    else if(0==strcmp(sql_result.protocol,"modbus_tcp")){
        ctx = modbus_new_tcp(sql_result.ip_address, sql_result.port);
        modbus_set_debug(ctx, TRUE);
        if (modbus_connect(ctx) == -1) {
            fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
            modbus_free(ctx);
            //return -1;
        }
        if(0==strcmp(sql_result.register_type,"holding_register")){
            /*
            客户端的参数实际数据传递过来的时候，opc ua会为每个变量最多分配4个字节32位的缓冲区，
            （错误的认识）
            opc ua会根据传入的数据类型分配内存空间，占64位的long，就分配8个字节
            占32位的int，就分配4个字节，然后按照传入的参数个数津贴着，就是完整的一段连续的空间
            如果用32位的类型传递参数，但是实际的数值只用了16位
            */        
            //||0==strcmp(sql_result.register_type,"input_register")
            //input_register只读，不可写，modbus_write_registers不可以操作该类寄存器

            printf("arrayLength:%d\n",client_parm.arrayLength);
            //uint16_t* client_parm_array = (uint16_t*)malloc(sizeof(uint16_t)*client_parm.arrayLength);
            uint16_t* client_parm_array = (uint16_t*)client_parm.data;
            //之前用node-red的时候，没有指定数组型value的长度
            // for(int i=0;i<5;i++){
            //     printf("0x%04X",client_parm_array[i]);
            // }   
            char* json_str =  OPC_var_to_JSON(client_parm.data,client_parm.arrayLength,UA_TYPES_INT16);
            SQL_insert_opc_history_data(sql_result.name,json_str);  
            free(json_str);
            //将读出的数值写入到modbus寄存器里面
            int rc = modbus_write_registers(ctx, 
                sql_result.begin_address, sql_result.offset_range, client_parm_array);
            if (rc != sql_result.offset_range) {
                printf("ERROR modbus_write_registers (%d)\n", rc);
            }else{
                printf("Success modbus_write_registers (%d)\n", rc);
            }
        }else if(0==strcmp(sql_result.register_type,"coil")){    
            //||0==strcmp(sql_result.register_type,"discrete_input")
            //只读，不可写，modbus_write_bits只能操作coil
            printf("arrayLength:%d\n",client_parm.arrayLength);
            //因为传值的时候，只用到16位的数据类型里面的高8位，因此需要提取其中的奇数位
            //node red传coil数据的时候，一样需要使用uint16，因为网关的代码，当初是配合java去进行调试的，最低只支持到uint16
            //传uint8会报错111
            uint8_t* final_send = (uint8_t*)malloc(sizeof(uint8_t)*client_parm.arrayLength);
            uint8_t* client_parm_array = (uint8_t*)client_parm.data;  
            for(int i=0,j=0;i<client_parm.arrayLength*2;i+=2,j++){
                final_send[j] = client_parm_array[i];
                printf("%X\n",client_parm_array[i]);
            }
            char* json_str =  OPC_var_to_JSON(final_send,client_parm.arrayLength,UA_TYPES_BYTE);
            SQL_insert_opc_history_data(sql_result.name,json_str);  
            //将读出的数值写入到modbus寄存器里面
            int rc = modbus_write_bits(ctx, 
                sql_result.begin_address, sql_result.offset_range, final_send);
            if (rc != sql_result.offset_range) {
                printf("ERROR modbus_wrtie_bits (%d)\n", rc);
            }else{
                printf("Success modbus_wrtie_bits(%d)\n", rc);
            }
            free(final_send);
        }
        //OPC过程执行完成，暂时释放当前的modbus驱动
        //modbus_close(ctx);
        modbus_free(ctx);
    }else if(0==strcmp(sql_result.protocol,"modbus_rtu")){
        cJSON* rtu_param_json = cJSON_Parse(sql_result.rtu_param);
        cJSON* device = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "device");
        cJSON* baud = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "baud");
        cJSON* parity = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "parity");
        cJSON* data_bit = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "data_bit");
        cJSON* stop_bit = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "stop_bit");
        cJSON* server_id = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "server_id");
        cJSON* register_type = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "register_type");
        cJSON* begin_address = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "begin_address");
        cJSON* offset_range = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "offset_range");
        printf("%s %d %c %d %d\n",device->valuestring, 
            baud->valueint, 
            *(parity->valuestring), 
            data_bit->valueint, 
            stop_bit->valueint);
        ctx = modbus_new_rtu(device->valuestring, 
            baud->valueint, 
            *(parity->valuestring), 
            data_bit->valueint, 
            stop_bit->valueint);
        modbus_set_slave(ctx, server_id->valueint);    
        if(ctx == NULL){
            fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
            modbus_free(ctx);
            return;      
        }
        modbus_set_debug(ctx, TRUE);
        if (modbus_connect(ctx) == -1) {
            fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
            modbus_free(ctx);
            return;
            //return -1;
        }
        if(0==strcmp(register_type->valuestring,"holding_register")){
            /*
            客户端的参数实际数据传递过来的时候，opc ua会为每个变量最多分配4个字节32位的缓冲区，
            （错误的认识）
            opc ua会根据传入的数据类型分配内存空间，占64位的long，就分配8个字节
            占32位的int，就分配4个字节，然后按照传入的参数个数津贴着，就是完整的一段连续的空间
            如果用32位的类型传递参数，但是实际的数值只用了16位
            */        
            //||0==strcmp(sql_result.register_type,"input_register")
            //input_register只读，不可写，modbus_write_registers不可以操作该类寄存器

            printf("arrayLength:%d\n",client_parm.arrayLength);
            //uint16_t* client_parm_array = (uint16_t*)malloc(sizeof(uint16_t)*client_parm.arrayLength);
            uint16_t* client_parm_array = (uint16_t*)client_parm.data;   
            char* json_str =  OPC_var_to_JSON(client_parm.data,client_parm.arrayLength,UA_TYPES_INT16);
            SQL_insert_opc_history_data(sql_result.name,json_str);  
            free(json_str);
            //将读出的数值写入到modbus寄存器里面
            int rc = modbus_write_registers(ctx, 
                begin_address->valueint, offset_range->valueint, client_parm_array);
            if (rc != offset_range->valueint) {
                printf("ERROR modbus_write_registers (%d)\n", rc);
            }else{
                printf("Success modbus_write_registers (%d)\n", rc);
            }
        }else if(0==strcmp(register_type->valuestring,"coil")){    
            //||0==strcmp(sql_result.register_type,"discrete_input")
            //只读，不可写，modbus_write_bits只能操作coil
            printf("arrayLength:%d\n",client_parm.arrayLength);
            //因为传值的时候，只用到16位的数据类型里面的高8位，因此需要提取其中的奇数位
            uint8_t* final_send = (uint8_t*)malloc(sizeof(uint8_t)*client_parm.arrayLength);
            uint8_t* client_parm_array = (uint8_t*)client_parm.data;  
            for(int i=0,j=0;i<client_parm.arrayLength*2;i+=2,j++){
                final_send[j] = client_parm_array[i];
                printf("%X\n",client_parm_array[i]);
            }
            char* json_str =  OPC_var_to_JSON(final_send,client_parm.arrayLength,UA_TYPES_BYTE);
            SQL_insert_opc_history_data(sql_result.name,json_str);  
            //将读出的数值写入到modbus寄存器里面
            int rc = modbus_write_bits(ctx, 
                begin_address->valueint, offset_range->valueint, final_send);
            if (rc != offset_range->valueint) {
                printf("ERROR modbus_wrtie_bits (%d)\n", rc);
            }else{
                printf("Success modbus_wrtie_bits(%d)\n", rc);
            }
            free(final_send);
        }
        //OPC过程执行完成，暂时释放当前的modbus驱动
        //modbus_close(ctx);
        cJSON_Delete(rtu_param_json);
        modbus_free(ctx);
    }
}

void OPC_Modbus_RTU_Read(){
    cJSON* rtu_param_json = cJSON_Parse(sql_result.rtu_param);
    cJSON* device = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "device");
    cJSON* baud = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "baud");
    cJSON* parity = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "parity");
    cJSON* data_bit = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "data_bit");
    cJSON* stop_bit = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "stop_bit");
    cJSON* server_id = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "server_id");
    cJSON* register_type = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "register_type");
    cJSON* begin_address = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "begin_address");
    cJSON* offset_range = cJSON_GetObjectItemCaseSensitive(rtu_param_json, "offset_range");
    printf("%s %d %c %d %d\n",device->valuestring, 
        baud->valueint, 
        *(parity->valuestring), 
        data_bit->valueint, 
        stop_bit->valueint);
    ctx = modbus_new_rtu(device->valuestring, 
        baud->valueint, 
        *(parity->valuestring), 
        data_bit->valueint, 
        stop_bit->valueint);
    modbus_set_slave(ctx, server_id->valueint);    
    if(ctx == NULL){
        fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
        modbus_free(ctx);
        return;      
    }
    modbus_set_debug(ctx, TRUE);
    if (modbus_connect(ctx) == -1) {
        fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
        modbus_free(ctx);
        return;
        //return -1;
    }
    //缓冲区类型分为uint16_t和uint8_t两种
    UA_Variant value;
    uint16_t* tab_reg_u16 = NULL;
    uint8_t* tab_reg_u8 = NULL;
    if(0==strcmp(register_type->valuestring,"holding_register") || 
        0==strcmp(register_type->valuestring,"input_register") ){
            tab_reg_u16 = (uint16_t*)malloc(sizeof(uint16_t)*offset_range->valueint);
    }else if(0==strcmp(register_type->valuestring,"coil") ||
        0==strcmp(register_type->valuestring,"discrete_input")){
            tab_reg_u8 = (uint8_t*)malloc(sizeof(uint8_t)*offset_range->valueint);
    }
    
    //根据不同的寄存器类型读取数值
    if(0==strcmp(register_type->valuestring,"holding_register")){
        int  rc = modbus_read_registers(ctx, begin_address->valueint, offset_range->valueint, tab_reg_u16);  
        // if(rc == sql_result.offset_range){
        //     printf("read successful!!!");
        // }else{
        //     printf("read fail!!!");
        // }
    }else if(0==strcmp(register_type->valuestring,"input_register")){
        modbus_read_input_registers(ctx, begin_address->valueint, offset_range->valueint, tab_reg_u16);
    }else if(0==strcmp(register_type->valuestring,"coil")){
        modbus_read_bits(ctx, begin_address->valueint, offset_range->valueint, tab_reg_u8);
    }else if(0==strcmp(register_type->valuestring,"discrete_input")){
        modbus_read_input_bits(ctx, begin_address->valueint, offset_range->valueint, tab_reg_u8);
    }
    if(0==strcmp(register_type->valuestring,"holding_register") || 
        0==strcmp(register_type->valuestring,"input_register") ){
            //将读取的数组变更为OPC UA可以接受的形式
            UA_Variant_setArray(&value, 
                tab_reg_u16, offset_range->valueint, &UA_TYPES[UA_TYPES_INT16]);
    }else if(0==strcmp(register_type->valuestring,"coil") ||
        0==strcmp(register_type->valuestring,"discrete_input")){
            UA_Variant_setArray(&value, 
                tab_reg_u8, offset_range->valueint, &UA_TYPES[UA_TYPES_BYTE]);          
    }
    //把更新后的值，存入opc变量值的历史记录，这个记录里面的值不对底层协议作区分
    //值的部分，因为可能存在单个值，字符串，甚至再后续会引入结构体
    /* 创建一个JSON数据对象(链表头结点) */


    //UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-value-callback");
    //UA_NodeId currentNodeId = UA_NODEID_STRING(1, "HaoSheng");
    UA_NodeId currentNodeId = UA_NODEID_STRING(1,sql_result.name);
    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
    "[final]UA_NodeId :%u",currentNodeId.namespaceIndex);   
    
    //将新的值写入到之前的变量中  
    UA_Server_writeValue(haussentech_opc_server, currentNodeId, value); //测试目的，暂时注释掉
    
    //uint16在转换成int的时候会遇到很多的问题，要换成hex string的方式
    //后续json读取的时候也要把字符串转回数值
    char* temp_json_str = NULL; 
    //这个括号里面是可以使用变量的
    if(0==strcmp(register_type->valuestring,"holding_register") || 
        0==strcmp(register_type->valuestring,"input_register") ){

        temp_json_str = OPC_var_to_JSON(tab_reg_u16,offset_range->valueint,UA_TYPES_INT16);
    }else if(0==strcmp(register_type->valuestring,"coil") ||
        0==strcmp(register_type->valuestring,"discrete_input")){

        temp_json_str = OPC_var_to_JSON(tab_reg_u8,offset_range->valueint,UA_TYPES_BYTE);    
    }

    SQL_insert_opc_history_data(sql_result.name,temp_json_str);  
    free(temp_json_str);

    //正常功能下这个注释应该解开
    //将modbus缓存数据的空间进行释放，避免内存泄漏
    if(0==strcmp(register_type->valuestring,"holding_register") || 
        0==strcmp(register_type->valuestring,"input_register") ){
            //将读取的数组变更为OPC UA可以接受的形式
        free(tab_reg_u16);
    }else if(0==strcmp(register_type->valuestring,"coil") ||
        0==strcmp(register_type->valuestring,"discrete_input")){
        free(tab_reg_u8);          
    }
    //OPC过程执行完成，暂时释放当前的modbus驱动
    cJSON_Delete(rtu_param_json);
    modbus_close(ctx);
    modbus_free(ctx);
}


int OPC_Modbus_tcp_Read(){
    ctx = modbus_new_tcp(sql_result.ip_address, sql_result.port);
    //
    if(ctx == NULL){
        fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
        modbus_free(ctx);
        return -1;      
    }
    modbus_set_debug(ctx, TRUE);
    if (modbus_connect(ctx) == -1) {
        fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
        modbus_free(ctx);
        return -1;
        //return -1;
    }

    //缓冲区类型分为uint16_t和uint8_t两种
    UA_Variant value;
    uint16_t* tab_reg_u16 = NULL;
    uint8_t* tab_reg_u8 = NULL;
    if(0==strcmp(sql_result.register_type,"holding_register") || 
        0==strcmp(sql_result.register_type,"input_register") ){
            tab_reg_u16 = (uint16_t*)malloc(sizeof(uint16_t)*sql_result.offset_range);
    }else if(0==strcmp(sql_result.register_type,"coil") ||
        0==strcmp(sql_result.register_type,"discrete_input")){
            tab_reg_u8 = (uint8_t*)malloc(sizeof(uint8_t)*sql_result.offset_range);
    }
    
    //根据不同的寄存器类型读取数值
    if(0==strcmp(sql_result.register_type,"holding_register")){
        int  rc = modbus_read_registers(ctx, sql_result.begin_address, sql_result.offset_range, tab_reg_u16);  
        if(rc == sql_result.offset_range){
            printf("read successful!!!");
        }else{
            printf("read fail!!!");
        }
    }else if(0==strcmp(sql_result.register_type,"input_register")){
        modbus_read_input_registers(ctx, sql_result.begin_address, sql_result.offset_range, tab_reg_u16);
    }else if(0==strcmp(sql_result.register_type,"coil")){
        modbus_read_bits(ctx, sql_result.begin_address, sql_result.offset_range, tab_reg_u8);
    }else if(0==strcmp(sql_result.register_type,"discrete_input")){
        modbus_read_input_bits(ctx, sql_result.begin_address, sql_result.offset_range, tab_reg_u8);
    }
    if(0==strcmp(sql_result.register_type,"holding_register") || 
        0==strcmp(sql_result.register_type,"input_register") ){
            //将读取的数组变更为OPC UA可以接受的形式
            UA_Variant_setArray(&value, 
                tab_reg_u16, sql_result.offset_range, &UA_TYPES[UA_TYPES_INT16]);
    }else if(0==strcmp(sql_result.register_type,"coil") ||
        0==strcmp(sql_result.register_type,"discrete_input")){
            UA_Variant_setArray(&value, 
                tab_reg_u8, sql_result.offset_range, &UA_TYPES[UA_TYPES_BYTE]);          
    }
    //把更新后的值，存入opc变量值的历史记录，这个记录里面的值不对底层协议作区分
    //值的部分，因为可能存在单个值，字符串，甚至再后续会引入结构体
    /* 创建一个JSON数据对象(链表头结点) */


    //UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-value-callback");
    //UA_NodeId currentNodeId = UA_NODEID_STRING(1, "HaoSheng");
    UA_NodeId currentNodeId = UA_NODEID_STRING(1,sql_result.name);
    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
    "[final]UA_NodeId :%u",currentNodeId.namespaceIndex);   
    
    //将新的值写入到之前的变量中  
    UA_Server_writeValue(haussentech_opc_server, currentNodeId, value); //测试目的，暂时注释掉
    
    //uint16在转换成int的时候会遇到很多的问题，要换成hex string的方式
    //后续json读取的时候也要把字符串转回数值
    char* temp_json_str = NULL; 
    //这个括号里面是可以使用变量的
    if(0==strcmp(sql_result.register_type,"holding_register") || 
        0==strcmp(sql_result.register_type,"input_register") ){

        temp_json_str = OPC_var_to_JSON(tab_reg_u16,sql_result.offset_range,UA_TYPES_INT16);
    }else if(0==strcmp(sql_result.register_type,"coil") ||
        0==strcmp(sql_result.register_type,"discrete_input")){

        temp_json_str = OPC_var_to_JSON(tab_reg_u8,sql_result.offset_range,UA_TYPES_BYTE);    
    }

    SQL_insert_opc_history_data(sql_result.name,temp_json_str);  
    free(temp_json_str);

    //正常功能下这个注释应该解开
    //将modbus缓存数据的空间进行释放，避免内存泄漏
    if(0==strcmp(sql_result.register_type,"holding_register") || 
        0==strcmp(sql_result.register_type,"input_register") ){
            //将读取的数组变更为OPC UA可以接受的形式
        free(tab_reg_u16);
    }else if(0==strcmp(sql_result.register_type,"coil") ||
        0==strcmp(sql_result.register_type,"discrete_input")){
        free(tab_reg_u8);          
    }
    //OPC过程执行完成，暂时释放当前的modbus驱动
    modbus_close(ctx);
    modbus_free(ctx);
    return 0;
}
/*
it should change profoundly according to the protocol driver
which means add more if---else case to count different situation
*/
void OPC_Update_Value(UA_Server *server,char* var_name) {
    //获取变量名对应的协议类型
    sql_cb_done = false;
    sql_selet_get_var_protocol(var_name);
    while (!sql_cb_done)
    {
        //sql_cb_done为全局变量，循环等待回调函数执行结束，将其设为真
        //继续执行，目的就是把涉及到回调函数的场景，能够变成顺序执行
        //而不是陷入层层嵌套的回调地狱
    }   
    sql_cb_done = false;
    sql_select_get_var_protocol_config(var_name);
    while (!sql_cb_done)
    {

    }
    if(0==strcmp(sql_result.protocol,"dlt_645")){
        cJSON* dlt645_param_json = cJSON_Parse(sql_result.dlt645_param);
        //dic代表数据类型
        cJSON* dic = cJSON_GetObjectItemCaseSensitive(dlt645_param_json, "dic");
        //address代表电表设备的地址
        cJSON* address = cJSON_GetObjectItemCaseSensitive(dlt645_param_json, "address");
        //address代表电表设备的地址
        cJSON* device = cJSON_GetObjectItemCaseSensitive(dlt645_param_json, "device");
        //建立通讯的过程，引入全局变量和函数
        dlt645_port_init(device->valuestring);
        //dlt645_read_test()
        uint8_t test_addr[6] = {0x00,0x00,0x21,0x00,0x00,0x75};
		int ArrLen = cJSON_GetArraySize(address);
		for (int i = 0; i < ArrLen; i++)
		{
			cJSON * ArrStrEle = cJSON_GetArrayItem(address, i);
			if(NULL == ArrStrEle)
			{
			    continue;
			}
            test_addr[i] = ArrStrEle->valueint;
			printf("value[%d] : [%2x]\n", i,test_addr[i]);
		}     
        uint8_t read_buf[4];
        //rt_memset(read_buf, 0, 4);
        memset(read_buf, 0, 4);
        //设置从机地址
        dlt645_set_addr(&dlt645,test_addr);
        //if(dlt645_read_data(&dlt645,DLT645_1997_READ_TEST_CODE,read_buf,DLT645_1997) > 0) //1997采集测试
        if(dlt645_read_data(&dlt645,dic->valueint,read_buf,DLT645_2007) > 0)  //2007采集测试
        {
            float watt_val = *(float *)read_buf;
            printf("读取成功,组合有功总电能为: %.2f \r\n",*(float *)read_buf);
            UA_Variant value;
            uint16_t* tab_reg_u16 = NULL;
            UA_Variant_setArray(&value, &watt_val, 1, &UA_TYPES[UA_TYPES_FLOAT]);
            UA_NodeId currentNodeId = UA_NODEID_STRING(1,sql_result.name);
            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                "[final]UA_NodeId :%u",currentNodeId.namespaceIndex);   
            //将新的值写入到之前的变量中  
            cJSON* temp_buf = cJSON_CreateObject();
            //转换成json格式的时候会第丢失小数位的精度，因此需要乘上100
            cJSON_AddNumberToObject(temp_buf, "value", watt_val*100);          
            SQL_insert_opc_history_data(var_name,cJSON_Print(temp_buf));
            cJSON_Delete(temp_buf);
            UA_Server_writeValue(haussentech_opc_server, currentNodeId, value); //测试目的，暂时注释掉
        }
        else
        {
            printf("读取失败\r\n");
            
        }
        dlt645_close_connection();
        //完成连接动作以后，释放JSON参数
        cJSON_Delete(dlt645_param_json);
    }
    if(0==strcmp(sql_result.protocol,"modbus_tcp")){
        if(OPC_Modbus_tcp_Read()==-1){
            /*
                这个也带出了运行时异常的一个处理方法，就是opc在读取变量值时，就没有发生更新，一直都是之前的那个值，
                或者我们专门设置一个值，这个值在系统里面会被识别成异常，比如开关量的0和1，我们在底层驱动通信异常时返回-1

                经过测试我们发现，其实返回opc变量的值，不需要和设置的值时一致的，甚至数据类型都可以变更
                比如之前用float或者无符号整数去存储电压个各种模拟量数据，后买年将它返回的类型，设置成有符号的整数，并且为-1
                云端只要校验这个值，就能确定，底层的设备驱动是否存在失去链接的情况
            */
            UA_Int32 myInteger = -1;
            UA_Variant myVar;
            UA_Variant_init(&myVar);
            UA_NodeId currentNodeId = UA_NODEID_STRING(1,var_name);
            UA_Variant_setScalar(&myVar, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
            UA_Server_writeValue(server, currentNodeId, myVar);
            //
            return;            
        }else{
            return;
        }
    }else if(0==strcmp(sql_result.protocol,"modbus_rtu")){
        OPC_Modbus_RTU_Read();
    }else if(0==strcmp(sql_result.protocol,"iec_104")){
        handler_done = false;

        //把IEC104客户端的方
        CS104_Connection con = CS104_Connection_create(
            sql_result.iec_ip_address, sql_result.iec_port);
        printf("Connecting to: %s:%i\n", sql_result.iec_ip_address, sql_result.iec_port);
        CS101_AppLayerParameters alParams = CS104_Connection_getAppLayerParameters(con);
        alParams->originatorAddress = 3;
        CS104_Connection_setConnectionHandler(con, connectionHandler, NULL);
        CS104_Connection_setASDUReceivedHandler(con, asduReceivedHandler, NULL);
        /* uncomment to log messages */
        //CS104_Connection_setRawMessageHandler(con, rawMessageHandler, NULL);

        if (CS104_Connection_connect(con)) {
            printf("Connected!\n");

            CS104_Connection_sendStartDT(con);
            /*
            开始读取读取JSON里面的数据,首先获得大的对喜爱嗯
            */
           CS104_Connection_sendInterrogationCommand(con, CS101_COT_ACTIVATION, 1, IEC60870_QOI_STATION);
        }
        else{
            printf("Connect failed!\n");
            //IEC104连接异常的情况下直接return结束，返回的也是opc变量注册时的默认值
            /*
                这个也带出了运行时异常的一个处理方法，就是opc在读取变量值时，就没有发生更新，一直都是之前的那个值，
                或者我们专门设置一个值，这个值在系统里面会被识别成异常，比如开关量的0和1，我们在底层驱动通信异常时返回-1

                经过测试我们发现，其实返回opc变量的值，不需要和设置的值时一致的，甚至数据类型都可以变更
                比如之前用float或者无符号整数去存储电压个各种模拟量数据，后买年将它返回的类型，设置成有符号的整数，并且为-1
                云端只要校验这个值，就能确定，底层的设备驱动是否存在失去链接的情况
            */
            UA_Int32 myInteger = -1;
            UA_Variant myVar;
            UA_Variant_init(&myVar);
            UA_NodeId currentNodeId = UA_NODEID_STRING(1,var_name);
            UA_Variant_setScalar(&myVar, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
            UA_Server_writeValue(server, currentNodeId, myVar);
            //
            return;
        }
        
        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
            "wait_data\n"); 
        while(!handler_done){

        }       
        //针对两种情况,一定要注意全称，不能多一个空格
        cJSON* p_param = cJSON_Parse(sql_result.iec_param);
        //获取客户端传来的是UA_Variant client_parm，获取里面data，转换出和客户端传数组时对应的个时
        //printf("arrayLength:%d\n",client_parm.arrayLength);
        //参数进来的时候是int，这里就要用int，不然会出问题
        cJSON* p_ios = cJSON_GetObjectItemCaseSensitive(p_param, "ios");
        cJSON* p_select = cJSON_GetObjectItemCaseSensitive(p_param, "select");    
        int inter_size = cJSON_GetArraySize(p_ios);    
        if(0==strcmp(sql_result.iec_typeid,"M_ME_NB_1") || 
            0==strcmp(sql_result.iec_typeid,"C_SE_NB_1")){
            //其实用一个定长的数组也不是不行
            int* inter_result = (int*)malloc(sizeof(int)*inter_size);  
            const cJSON *p_io;
            int index = 0;
            cJSON_ArrayForEach(p_io, p_ios){
                printf("one inter\n");
                cJSON *p_ioa = cJSON_GetObjectItemCaseSensitive(p_io, "ioa");
                cJSON *p_value = cJSON_GetObjectItemCaseSensitive(p_io, "value");
                inter_result[index] = ioa_buffer[p_ioa->valueint];
                printf("%d\n",inter_result[index]);
                // CS101_ASDU_addInformationObject(newAsdu, (InformationObject)
                //     SetpointCommandScaled_create(NULL, p_ioa->valueint, client_parm_array[index], cJSON_IsTrue(p_select), 0));
                index++;
            }
            UA_Variant value;
            //将读取的数组变更为OPC UA可以接受的形式,要注意UA_TYPES_INT32
            //把缓冲区里面的值，标记上起始地址和偏移范围以后
            UA_Variant_setArray(&value,inter_result,inter_size, &UA_TYPES[UA_TYPES_INT32]);
            //UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-value-callback");
            //UA_NodeId currentNodeId = UA_NODEID_STRING(1, "HaoSheng");
            UA_NodeId currentNodeId = UA_NODEID_STRING(1,var_name);
            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
            "[final]UA_NodeId :%u",currentNodeId.namespaceIndex);   
            //将新的值写入到之前的变量中    
            UA_Server_writeValue(server, currentNodeId, value);
            free(inter_result);
        }
        //浮点数类型的西悉尼
        if(0==strcmp(sql_result.iec_typeid,"M_ME_NC_1")){
            //其实用一个定长的数组也不是不行
            float* inter_result = (float*)malloc(sizeof(float)*inter_size);  
            const cJSON *p_io;
            int index = 0;
            //迭代json数据是获取配置信息，关于ioa点表的配置
            cJSON_ArrayForEach(p_io, p_ios){
                printf("one inter\n");
                cJSON *p_ioa = cJSON_GetObjectItemCaseSensitive(p_io, "ioa");
                inter_result[index] = ioa_float_buffer[p_ioa->valueint];
                printf("%3.2f\n",inter_result[index]);
                index++;
            }
            UA_Variant value;
            //将读取的数组变更为OPC UA可以接受的形式,要注意UA_TYPES_INT32
            //把缓冲区里面的值，标记上起始地址和偏移范围以后
            UA_Variant_setArray(&value,inter_result,inter_size, &UA_TYPES[UA_TYPES_FLOAT]);
            //UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-value-callback");
            //UA_NodeId currentNodeId = UA_NODEID_STRING(1, "HaoSheng");
            UA_NodeId currentNodeId = UA_NODEID_STRING(1,var_name);
            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
            "[final]UA_NodeId :%u",currentNodeId.namespaceIndex);   
            //将新的值写入到之前的变量中    
            UA_Server_writeValue(server, currentNodeId, value);
            //在存储数值之前，首先需要把数组理成相接的形式，并且是先用sprintf转化成字符串的形式，再放到json中的
            char* json_str =  OPC_var_to_JSON(inter_result,inter_size,UA_TYPES_FLOAT);
            SQL_insert_opc_history_data(var_name,json_str);  
            free(inter_result);
            free(json_str);
        }
        //开关量信息   
        if(0==strcmp(sql_result.iec_typeid,"M_SP_NA_1")){
            //其实用一个定长的数组也不是不行
            bool* inter_result = (bool*)malloc(sizeof(bool)*inter_size);  
            const cJSON *p_io;
            int index = 0;
            //迭代json数据是获取配置信息，关于ioa点表的配置
            cJSON_ArrayForEach(p_io, p_ios){
                printf("one inter\n");
                cJSON *p_ioa = cJSON_GetObjectItemCaseSensitive(p_io, "ioa");
                inter_result[index] = ioa_bool_buffer[p_ioa->valueint];
                printf("%d\n",inter_result[index]);
                index++;
            }
            UA_Variant value;
            //将读取的数组变更为OPC UA可以接受的形式,要注意UA_TYPES_INT32
            //把缓冲区里面的值，标记上起始地址和偏移范围以后
            UA_Variant_setArray(&value,inter_result,inter_size, &UA_TYPES[UA_TYPES_BOOLEAN]);
            //UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-value-callback");
            //UA_NodeId currentNodeId = UA_NODEID_STRING(1, "HaoSheng");
            UA_NodeId currentNodeId = UA_NODEID_STRING(1,var_name);
            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                "[final]UA_NodeId :%u",currentNodeId.namespaceIndex);   
            //将新的值写入到之前的变量中    
            UA_Server_writeValue(server, currentNodeId, value);
            free(inter_result);
        }       
        //Thread_sleep(1000);
        CS104_Connection_destroy(con);
        printf("exit\n");    
    }
}
/* Callback handler to log sent or received messages (optional) */
static void
rawMessageHandler (void* parameter, uint8_t* msg, int msgSize, bool sent)
{
    if (sent)
        printf("SEND: ");
    else
        printf("RCVD: ");

    int i;
    for (i = 0; i < msgSize; i++) {
        printf("%02x ", msg[i]);
    }

    printf("\n");
}

/* Connection event handler */
static void
connectionHandler (void* parameter, CS104_Connection connection, CS104_ConnectionEvent event)
{
    switch (event) {
    case CS104_CONNECTION_OPENED:
        printf("Connection established\n");
        break;
    case CS104_CONNECTION_CLOSED:
        printf("Connection closed\n");
        break;
    case CS104_CONNECTION_STARTDT_CON_RECEIVED:
        printf("Received STARTDT_CON\n");
        break;
    case CS104_CONNECTION_STOPDT_CON_RECEIVED:
        printf("Received STOPDT_CON\n");
        break;
    }
}

/*
 * CS101_ASDUReceivedHandler implementation
 *
 * For CS104 the address parameter has to be ignored
 */
static bool
asduReceivedHandler (void* parameter, int address, CS101_ASDU asdu)
{
    printf("RECVD ASDU type: %s(%i) elements: %i\n",
            TypeID_toString(CS101_ASDU_getTypeID(asdu)),
            CS101_ASDU_getTypeID(asdu),
            CS101_ASDU_getNumberOfElements(asdu));
    int require_typeid;
    if(0==strcmp(sql_result.iec_typeid,"M_ME_NB_1")){
        require_typeid = M_ME_NB_1;
    }
    if(0==strcmp(sql_result.iec_typeid,"M_ME_NC_1")){
        require_typeid = M_ME_NC_1;
    }
    if(0==strcmp(sql_result.iec_typeid,"M_SP_NA_1")){
        require_typeid = M_SP_NA_1;
    }
    //因为IEC104的服务器会返回各种类型的报文，首先要保证该类型是用户请求的
    if(CS101_ASDU_getTypeID(asdu) == require_typeid){
        if(CS101_ASDU_getTypeID(asdu) == M_ME_NB_1){
            printf("  measured scaled values :\n");
            int i;
            //自动获取ASDU报文里携带的变量数量，报文又被称为帧，帧的本质就是缓存中的一组约定格式的数据
            //通常用数组来表示，这些协议已经屏蔽了直接的帧操作，让用户调用函数去处理
            for (i = 0; i < CS101_ASDU_getNumberOfElements(asdu); i++) {
                MeasuredValueScaled io =
                        (MeasuredValueScaled) CS101_ASDU_getElement(asdu, i);

                printf("    IOA: %i value: %i\n",
                        InformationObject_getObjectAddress((InformationObject) io),
                        MeasuredValueScaled_getValue((MeasuredValueScaled) io)
                );
                ioa_buffer[InformationObject_getObjectAddress((InformationObject) io)]=
                    MeasuredValueScaled_getValue((MeasuredValueScaled) io);
                MeasuredValueScaled_destroy(io);
            }
            handler_done = true;
        }
        if(CS101_ASDU_getTypeID(asdu) == M_ME_NC_1){
            printf("  three-phase voltage float values :\n");
            int i;
            //自动获取ASDU报文里携带的变量数量，报文又被称为帧，帧的本质就是缓存中的一组约定格式的数据
            //通常用数组来表示，这些协议已经屏蔽了直接的帧操作，让用户调用函数去处理
            for (i = 0; i < CS101_ASDU_getNumberOfElements(asdu); i++) {
                MeasuredValueShort io =
                        (MeasuredValueShort) CS101_ASDU_getElement(asdu, i);

                printf("    IOA: %i value: %3.2f\n",
                        InformationObject_getObjectAddress((InformationObject) io),
                        MeasuredValueShort_getValue((MeasuredValueShort) io)
                );
                ioa_float_buffer[InformationObject_getObjectAddress((InformationObject) io)]=
                    MeasuredValueShort_getValue((MeasuredValueShort) io);
                MeasuredValueShort_destroy(io);
            }
            handler_done = true;
        }
        if(CS101_ASDU_getTypeID(asdu) == M_SP_NA_1){
            printf("  switch-state values :\n");
            int i;
            //自动获取ASDU报文里携带的变量数量，报文又被称为帧，帧的本质就是缓存中的一组约定格式的数据
            //通常用数组来表示，这些协议已经屏蔽了直接的帧操作，让用户调用函数去处理
            for (i = 0; i < CS101_ASDU_getNumberOfElements(asdu); i++) {
                SinglePointInformation io =
                        (SinglePointInformation) CS101_ASDU_getElement(asdu, i);

                printf("    IOA: %i state: %d\n",
                        InformationObject_getObjectAddress((InformationObject) io),
                        SinglePointInformation_getValue((SinglePointInformation) io)
                );
                ioa_bool_buffer[InformationObject_getObjectAddress((InformationObject) io)]=
                    SinglePointInformation_getValue((SinglePointInformation) io);
                MeasuredValueShort_destroy(io);
            }
            handler_done = true;
        }
    }
    return true;
}
void SQL_insert_opc_history_data(char* opc_var_name,char* opc_var_data){
    //在函数内插入系统时间
    char updata_time[20];
    time_t now = time(NULL);
    strftime(updata_time, 20, "%Y-%m-%d %H:%M:%S", localtime(&now));
    //printf("[var_name]:%S\n",sql_result.name);

    char sql[512] = "INSERT INTO opc_history_data (name,data,date) "  \
            "VALUES ";
    char* separate_begin = ", '";
    char* separate_end =  "'";
    char* sentence_end =  ");";
    char* num_sep= ", ";
    char* sentence_begin = "('";

    strcat(sql,sentence_begin);
    strcat(sql,opc_var_name);
    strcat(sql,separate_end);

    strcat(sql,separate_begin);
    strcat(sql,opc_var_data);
    strcat(sql,separate_end);
    
    strcat(sql,separate_begin);
    strcat(sql,updata_time);
    strcat(sql,separate_end);
    strcat(sql,sentence_end);

    printf("\n[SQL statement Debug]\n%s\n[SQL statement Debug]\n",sql);
    /* Execute SQL statement */
    int rc;
    char *zErrMsg = 0;
    rc = sqlite3_exec(db, sql, NULL, 0, &zErrMsg);
    if( rc != SQLITE_OK ){
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        //遇到异常重启程序的指令，在开发阶段不使用
        //execve("opc", NULL, NULL);
        sqlite3_free(zErrMsg);
    }else{
        fprintf(stdout, "Records created successfully\n");
    }
}